package com.example.demo.service.impl;

import com.example.demo.dao.DishesDao;
import com.example.demo.dao.UserDao;
import com.example.demo.model.Dishes;
import com.example.demo.model.Ingredients;
import com.example.demo.model.User;
import com.example.demo.model.ViewedDishNode;
import com.example.demo.service.RecommendationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class RecommendationServiceImpl implements RecommendationService {
    @Autowired(required = false)
    private UserDao userDao;
    @Autowired
    private DishesDao dishesDao;

    @Override
    public List<Ingredients> getRecommendedIngredients(String name) {
        User user = userDao.findByName(name);
        List<Ingredients> recommendedIngredients = new ArrayList<>();

        List<ViewedDishNode> viewedDishNodes = user.getViewedDishNodes();

        if (viewedDishNodes != null && !viewedDishNodes.isEmpty()) {
            Map<Ingredients, Integer> viewedIngredientFrequencyMap = new HashMap<>();

            // 统计浏览过的菜品中食材的出现次数
            for (ViewedDishNode node : viewedDishNodes) {
                // 根据 dishId 获取对应的菜品信息
                Dishes dish = dishesDao.selectByPrimaryKey(node.getDishId());
                if (dish != null) {
                    List<Ingredients> dishIngredients = dish.getDIngredients();
                    for (Ingredients ingredient : dishIngredients) {
                        viewedIngredientFrequencyMap.put(ingredient, viewedIngredientFrequencyMap.getOrDefault(ingredient, 0) + 1);
                    }
                }
            }

            // 对食材按照出现频率进行排序
            List<Map.Entry<Ingredients, Integer>> sortedViewedIngredients = new ArrayList<>(viewedIngredientFrequencyMap.entrySet());
            sortedViewedIngredients.sort((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()));

            // 选出浏览过菜品中出现频率最高的三种食材
            int count = 0;
            for (Map.Entry<Ingredients, Integer> entry : sortedViewedIngredients) {
                recommendedIngredients.add(entry.getKey());
                count++;
                if (count >= 3) {
                    break;
                }
            }
        }

        return recommendedIngredients;
    }

    @Override
    public List<Dishes> getRecommendedFood(String name) {
        User newUser = userDao.findByName(name);
        List<User> users = userDao.findAll();
        // 计算用户之间的距离
        Map<User, Double> userDistances = new HashMap<>();
        for (User user : users) {
            double distance = calculateDistance(newUser, user);
            userDistances.put(user, distance);
        }
        // 找出距离最小的前十个用户
        List<User> similarUsers = userDistances.entrySet().stream()
                .sorted(Map.Entry.comparingByValue())
                .limit(10)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());

        // 将这些用户观看的菜品推荐给新用户
        List<Dishes> recommendedDishes = new ArrayList<>();
        for (User user : similarUsers) {
            if (user.getViewedDishNodes() != null && !user.getViewedDishNodes().isEmpty()) {
                ViewedDishNode currentNode = user.getViewedDishNodes().get(0); // 获取链表的头节点
                while (currentNode != null) {
                    Dishes dish = dishesDao.selectByPrimaryKey(currentNode.getDishId());
                    if (dish != null && !newUser.getViewedDishNodes().contains(currentNode)) {
                        recommendedDishes.add(dish);
                    }
                    currentNode = currentNode.getNextNode(); // 移动到下一个节点
                }
            }
        }

        // 输出推荐结果
        System.out.println("Recommended meals for new user:");
        for (Dishes dish : recommendedDishes) {
            System.out.println(dish);
        }
        return recommendedDishes;
    }

    public static double calculateDistance(User user1, User user2) {
        // 这里可以根据年龄、性别、地区等特征计算距离
        return Math.abs(user1.getAge() - user2.getAge());
    }
}
